package infoimport

import (
	"fmt"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/config"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/dao"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/entity"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/global"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/crypto"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/file"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/model"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/util"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

func GetFileSize(filePath string) int64 {
	file, _ := os.Open(filePath)
	fileInfo, _ := file.Stat()
	defer file.Close()
	fileSize := fileInfo.Size()
	return fileSize
}

//导入Excel
func ImportExcel(c *gin.Context) {

	global.Log.Info("ImportExcel() start.")
	type ImportLog struct {
		ApplicantId int64     //申请人
		FilePath    string    //文件路径
		StartDate   time.Time //导入开始时间
		EndDate     time.Time //导入结束时间
		RowTotal    int       //总行数
		UserTotal   int       //用户总数
		DeptTotal   int       //部门总数
		AddUserNum  int       //添加用户数量
		AddDetpNum  int       //新增部门数量
	}
	var importSum ImportLog
	importSum.StartDate = time.Now()

	//todo. 此处需要判别当前请求发起者身份，如果非Hr，则驳回，无此操作权限
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	if requester.Role != entity.EEmployeeRole_Hr {
		global.Log.Error("ImportExcel auth only for hr.", zap.Any("requester", requester))
		c.JSON(http.StatusOK, model.Fail("只有HR管理员才能导入信息"))
		return
	}

	formFile, header, err := c.Request.FormFile("excelFile") //文件
	if err != nil {
		global.Log.Error("upload file failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("上传文件异常"))
		return
	}
	filename := header.Filename
	ext := path.Ext(filename) //扩展名
	allow := ".xlsx"
	if strings.Index(allow, strings.ToLower(ext)) < 0 {
		global.Log.Info("ImportExcel file format error.", zap.Any("ext", filename))
		c.JSON(http.StatusBadRequest, model.Fail("文件格式不正确"))
		return
	}

	randomStr := string(util.RandomCreateBytes(10))
	uploadDir := config.Server().UploadDir
	filename = path.Join(uploadDir, "attence", randomStr+path.Ext(filename))
	out, err := file.CreateFile(filename) //file 在git环境中需要改包路径
	defer out.Close()
	if err != nil {
		global.Log.Error("ImportExcel create file error.", zap.Any("filename", filename), zap.Any("error", err))
		c.JSON(http.StatusOK, err.Error())
		return
	}

	_, err = io.Copy(out, formFile)
	if err != nil {
		global.Log.Error("ImportExcel io.Copy error.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("数据异常，"+err.Error()))
		return
	}

	fileSize := GetFileSize(out.Name())
	if fileSize > 1048576 { // >1M 大小
		global.Log.Error("ImportExcel file size is too big.", zap.Any("fileSize", fileSize))
		c.JSON(http.StatusOK, model.Fail("上传文件大小超过限制")) //10M
		return
	}

	global.Log.Info("ImportExcel create excel file success.", zap.Any("filename", filename))

	/*
		filepath := c.DefaultPostForm("filepath", "")
		if len(filepath) <= 0 {
			global.Log.Error("excelFile is none.")
			c.JSON(http.StatusOK, model.Fail("未指明导入文件"))
			return
		}*/
	importSum.FilePath = filename
	xlsx, err := excelize.OpenFile(filename)
	if err != nil {
		global.Log.Error("excelFile open failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("打开文件失败"))
		return
	}

	//获取 sheet页上所有单元格  data是我的工作表的名称
	rows := xlsx.GetRows(xlsx.GetSheetName(1))
	if len(rows) <= 0 {
		global.Log.Error("excelFile rows is none.")
		c.JSON(http.StatusOK, model.Fail("导入文件中不包含数据"))
		return
	}

	tableTitle := rows[0] //表头校验
	if len(tableTitle) != 9 {
		global.Log.Error("excelFile rows is not ninth.")
		c.JSON(http.StatusOK, model.Fail("导入文件数据列数不等于九"))
		return
	}
	if tableTitle[0] != "姓名" && tableTitle[0] != "name" {
		global.Log.Error("first column is not name.")
		c.JSON(http.StatusOK, model.Fail("第一列表头不是姓名"))
		return
	}
	if tableTitle[1] != "厂商信息" && tableTitle[1] != "vendor" {
		global.Log.Error("second column is not vendor.")
		c.JSON(http.StatusOK, model.Fail("第二列表头不是厂商信息"))
		return
	}
	if tableTitle[2] != "部门" && tableTitle[2] != "department" {
		global.Log.Error("third column is not department.")
		c.JSON(http.StatusOK, model.Fail("第三列表头不是部门"))
		return
	}
	if tableTitle[3] != "部门负责人" && tableTitle[3] != "dept leader" {
		global.Log.Error("fourth column is not dept leader.")
		c.JSON(http.StatusOK, model.Fail("第四列表头不是部门负责人"))
		return
	}
	if tableTitle[4] != "手机" && tableTitle[4] != "mobile" {
		global.Log.Error("fifth column is not mobile.")
		c.JSON(http.StatusOK, model.Fail("第五列表头不是手机"))
		return
	}
	if tableTitle[5] != "个人邮箱" && tableTitle[5] != "email" {
		global.Log.Error("sixth column is not email.")
		c.JSON(http.StatusOK, model.Fail("第六列表头不是手机"))
		return
	}
	if tableTitle[6] != "人员类别" && tableTitle[6] != "employee type" {
		global.Log.Error("seventh column is not employee type.")
		c.JSON(http.StatusOK, model.Fail("第七列表头不是人员类别"))
		return
	}
	if tableTitle[7] != "上班时间" && tableTitle[7] != "work_start" {
		global.Log.Error("eighth column is not work_start.")
		c.JSON(http.StatusOK, model.Fail("第八列表头不是上班时间"))
		return
	}
	if tableTitle[8] != "下班时间" && tableTitle[8] != "work_end" {
		global.Log.Error("ninth column is not work_end.")
		c.JSON(http.StatusOK, model.Fail("第九列表头不是下班时间"))
		return
	}

	type EmployeeInfo struct { //可用“姓名+手机号”作为Key值，用来关联新的和已有的员工信息
		Id        int64  `xorm:"pk"`
		Name      string //姓名（必填）
		Mobile    string //手机（必填）
		Email     string //邮件
		Dept      string //所属部门ID（必填）
		Leader    string //主管领导ID（必填）
		Vendor    string //厂商信息
		Type      string //当前员工类别：0：外包雇员；1：部门总监(司编雇员）；2：HR管理员
		WorkStart string //上班时间
		WorkEnd   string //下班时间
	}

	var importInfoList []EmployeeInfo //待导入信息列表
	msg := ""
	mobileNameMap := make(map[string]string)           //手机号信息，用来判断是否重复的手机号
	nameMobileInfoMap := make(map[string]EmployeeInfo) //Name+手机[信息]，用来记录新增信息
	importSum.RowTotal = len(rows)
	for i := 1; i < len(rows); i++ {
		row := rows[i]
		var employee EmployeeInfo
		employee.Name = strings.TrimSpace(row[0])
		employee.Vendor = strings.TrimSpace(row[1])
		employee.Dept = strings.TrimSpace(row[2])
		employee.Leader = strings.TrimSpace(row[3])
		employee.Mobile = strings.TrimSpace(row[4])
		employee.Email = strings.TrimSpace(row[5])
		employee.Type = strings.TrimSpace(row[6])
		employee.WorkStart = strings.TrimSpace(row[7])
		employee.WorkEnd = strings.TrimSpace(row[8])

		if employee.Name == "" {
			msg = fmt.Sprint("数据错误，第", i, "行，姓名为空")
			break
		}
		if employee.Dept == "" {
			msg = fmt.Sprint("数据错误，第", i, "行，部门为空")
			break
		}
		if employee.Mobile == "" {
			msg = fmt.Sprint("数据错误，第", i, "行，手机为空")
			break
		}
		if employee.Type != "外包员工" && employee.Type != "部门主管" && employee.Type != "人力主管" {
			msg = fmt.Sprint("数据错误，第", i, "行，存在不支持的人员类别")
			continue
		}
		_, has := mobileNameMap[employee.Mobile]
		if has {
			msg = fmt.Sprint("数据错误，第", i, "行，手机号码重复.", employee.Mobile)
			break
		}
		mobileNameMap[employee.Mobile] = employee.Name
		nameMobileInfoMap[employee.Name+employee.Mobile] = employee
		importInfoList = append(importInfoList, employee)
	}

	if msg != "" {
		global.Log.Error("import data is error:" + msg)
		c.JSON(http.StatusOK, model.Fail(msg))
		return
	}
	if len(importInfoList) <= 0 {
		global.Log.Error("import data is none.")
		c.JSON(http.StatusOK, model.Fail("待导入的数据为空"))
		return
	}

	//==========================================
	deptTotal, deptExistList, err := dao.QueryDepartmentList(1, 0) //已存在的部门列表
	if err != nil {
		global.Log.Error("query exist depts failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("查询已有部门异常"))
		return
	}
	importSum.DeptTotal = int(deptTotal)
	global.Log.Info("department exist.", zap.Any("total", deptTotal), zap.Any("departments", deptExistList))
	//==========================================
	var deptIds []int64
	employeeTotal, employeeExistList, err := dao.QueryEmployeeList(1, 0, "", deptIds, -1, -1)
	//已存在的人员列表
	if err != nil {
		global.Log.Error("query exist depts failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("查询已有部门异常"))
		return
	}
	importSum.RowTotal = int(employeeTotal)
	global.Log.Info("department exist.", zap.Any("total", employeeTotal), zap.Any("employee list", employeeExistList))
	//==========================================

	existEmployeeMap := make(map[string]*entity.Employee, 0)  //外包员工[姓名+手机]*entity.Employee
	leaderEmployeeMap := make(map[string]*entity.Employee, 0) //部门领导[姓名]*entity.Employee
	hrEmployeeMap := make(map[string]*entity.Employee, 0)     //HR[姓名]*entity.Employee
	allEmployeeMap := make(map[string]*entity.Employee, 0)    //不分类，以上3种类别全记录

	for _, employee := range employeeExistList {
		if employee.Role == entity.EEmployeeRole_Hr {
			hrEmployeeMap[employee.Name] = employee
		} else if employee.Role == entity.EEmployeeRole_DeptLeader {
			leaderEmployeeMap[employee.Name] = employee
		} else if employee.Role == entity.EEmployeeRole_Outsourcing {
			existEmployeeMap[employee.Name+employee.Mobile] = employee
		}

		//检测一下新增手机是不是已经存在了。
		_, has := mobileNameMap[employee.Mobile]
		if has {
			global.Log.Error("mobile has exist. " + employee.Mobile)
			c.JSON(http.StatusOK, model.Fail("手机号已经存在了："+employee.Mobile))
			return
		}
		allEmployeeMap[employee.Name+employee.Mobile] = employee
	}

	//-------------------------
	existDeptMap := make(map[string]*entity.Department, 0)
	for _, dept := range deptExistList {
		existDeptMap[dept.DeptName] = dept
	}

	//------------------------
	var employeeListToAdd []entity.Employee
	var leaderListToAdd []entity.Employee
	var hrListToAdd []entity.Employee
	var deptListToAdd []entity.Department

	for _, info := range importInfoList {
		existEmployee, has := allEmployeeMap[info.Name+info.Mobile]
		if has {
			global.Log.Error("employee has exist.", zap.Any("info", info))
			c.JSON(http.StatusOK, model.Fail("员工已经存在"+existEmployee.Mobile))
			return
		}

		var newEmployee entity.Employee
		newEmployee.Mobile = info.Mobile
		newEmployee.Email = info.Email
		newEmployee.Name = info.Name
		newEmployee.Vendor = info.Vendor
		newEmployee.Password = info.Mobile
		newEmployee.WorkStart = info.WorkStart
		newEmployee.WorkEnd = info.WorkEnd

		cryptoInstance2, ok := global.Crypto.Digest[crypto.CryptoSM3]
		if ok {
			newEmployee.Password, err = cryptoInstance2.Sum([]byte(newEmployee.Password))
			if err != nil {
				global.Log.Error("global.Crypto.Digest CryptoSM3 Sum error.", zap.Any("error", err))
			} //此处Password已经变更为密码摘要
		} else {
			global.Log.Error("global.Crypto.Digest CryptoSM3 error,no found")
		}

		if info.Type == "外包员工" {
			newEmployee.Role = entity.EEmployeeRole_Outsourcing
		} else if info.Type == "部门主管" {
			newEmployee.Role = entity.EEmployeeRole_DeptLeader
		} else if info.Type == "人力主管" {
			newEmployee.Role = entity.EEmployeeRole_Hr
		}

		existDept, has := existDeptMap[info.Dept]
		if has {
			newEmployee.DeptId = existDept.DeptId //找到已经存在的部门及其ID
			if existDept.DeptHeadId > 0 {
				newEmployee.LeaderId = existDept.DeptHeadId //部门领导的id
			} else { //部门也没有设置领导ID，按姓名遍历查找一下
				for key, leader := range leaderEmployeeMap {
					fmt.Println(key)
					if leader.Name == info.Leader && info.Dept == existDept.DeptName {
						newEmployee.LeaderId = leader.Id
						break //找到了就用继续循环查找了
					}
				}
			}
		} else {
			//需要创建的部门
			var dept entity.Department
			dept.DeptName = info.Dept //这里记录部门的名字信息
			dept.DeptHead = info.Leader
			deptListToAdd = append(deptListToAdd, dept)
		}

		if newEmployee.Role == entity.EEmployeeRole_DeptLeader { //新增部门主管
			existEmployee, has = leaderEmployeeMap[info.Leader] //找到部门领导
			if has {
				newEmployee.LeaderId = existEmployee.LeaderId //leader 已经赋值
			} else {
				//需要创建部门领导.
			}
			leaderListToAdd = append(leaderListToAdd, newEmployee)
		} else if newEmployee.Role == entity.EEmployeeRole_Hr { //新增hr

			existEmployee, has = leaderEmployeeMap[info.Leader] //找到部门领导
			if has {
				newEmployee.LeaderId = 0 //leader 已经赋值
			}
			hrListToAdd = append(hrListToAdd, newEmployee)
		} else { //新增外包员工
			existEmployee, has = leaderEmployeeMap[info.Leader] //找到部门领导
			if has && newEmployee.LeaderId <= 0 {
				newEmployee.LeaderId = existEmployee.Id //leader 已经赋值
			}
			employeeListToAdd = append(employeeListToAdd, newEmployee)
		}
	}

	//先创建部门
	var newDeptList []*entity.Department
	for _, dept := range deptListToAdd {
		if dept.DeptHeadId <= 0 {
			existEmployee, has := leaderEmployeeMap[dept.DeptHead]
			if has {
				dept.DeptHeadId = existEmployee.Id
			}
		}
		newDept, err := dao.CreateDepartment(dept)
		if err != nil {
			fmt.Println(err)
			continue
		}
		if newDept == nil {
			continue
		}
		existDeptMap[dept.DeptName] = newDept
		newDeptList = append(newDeptList, newDept)
		fmt.Println(newDept)
	}

	//再创建人员
	importSum.AddDetpNum = len(deptListToAdd)
	importSum.AddUserNum = len(hrListToAdd) + len(leaderListToAdd) + len(employeeListToAdd)

	var newEmployeeList []*entity.Employee
	for _, hr := range hrListToAdd {
		if hr.DeptId <= 0 {
			info, has := nameMobileInfoMap[hr.Name+hr.Mobile]
			if has {
				deptInfo, has := existDeptMap[info.Dept] //找到这个人所在部门的名称，
				if has {
					hr.DeptId = deptInfo.DeptId
				}
			} //查找一下部门ID
		}

		newer, err := dao.InsertEmployee(hr)
		if err != nil {
			fmt.Println(err)
			continue
		}
		hrEmployeeMap[newer.Mobile] = newer
		allEmployeeMap[newer.Name+newer.Mobile] = newer
		newEmployeeList = append(newEmployeeList, newer)
		fmt.Println(newer)
	}

	for _, leader := range leaderListToAdd {
		if leader.DeptId <= 0 {
			info, has := nameMobileInfoMap[leader.Name+leader.Mobile]
			if has {
				deptInfo, has := existDeptMap[info.Dept] //找到这个人所在部门的名称，
				if has {
					leader.DeptId = deptInfo.DeptId
				}
			} //查找一下部门ID
		}

		newer, err := dao.InsertEmployee(leader)
		if err != nil {
			fmt.Println(err)
			continue
		}
		leaderEmployeeMap[newer.Mobile] = newer
		allEmployeeMap[newer.Name+newer.Mobile] = newer
		newEmployeeList = append(newEmployeeList, newer)
		fmt.Println(newer)
	}
	for _, employee := range employeeListToAdd {
		if employee.DeptId <= 0 {
			info, has := nameMobileInfoMap[employee.Name+employee.Mobile]
			if has {
				deptInfo, has := existDeptMap[info.Dept] //找到这个人所在部门的名称，
				if has {
					employee.DeptId = deptInfo.DeptId
					if employee.LeaderId <= 0 {
						employee.LeaderId = deptInfo.DeptHeadId
					}
				}
			}
		}

		if employee.LeaderId <= 0 {
			info, has := nameMobileInfoMap[employee.Name+employee.Mobile]
			if has { //领导名字
				leader, has := leaderEmployeeMap[info.Leader]
				if has {
					employee.LeaderId = leader.Id
				}
			}
		}
		newer, err := dao.InsertEmployee(employee)
		if err != nil {
			fmt.Println(err)
			continue
		}
		existEmployeeMap[newer.Mobile] = newer
		allEmployeeMap[newer.Name+newer.Mobile] = newer
		newEmployeeList = append(newEmployeeList, newer)
		fmt.Println(newer)
	}

	//将人员表中的空白ID部门填充
	for _, user := range newEmployeeList {
		if user.DeptId <= 0 {

		}
		if user.LeaderId <= 0 {

		}
	}

	//将部门表中的人员ID填充

	importSum.EndDate = time.Now()
	c.JSON(http.StatusOK, model.SuccessObject("操作成功", importSum))
	global.Log.Info("Import excel success.", zap.Any("import", importSum))
}
